package com.shujia

object Demo04Func02 {
  val i: String = "10"
  val j: Int = 100

  // func1是一个”以String以及Int作为参数，Int作为返回值“类型的函数
  // (String,Int) => Int
  def func1(str: String, int: Int): Int = {
    str.toInt + int
  }


  // (Int,String) => Int
  def func2(int: Int, str: String): Int = {
    str.toInt + int
  }

  // (String,Int) => Int
  def func3(str: String, int: Int): Int = {
    str.toInt + int + 100
  }

  // String => Int
  def func4(str: String): Int = {
    str.toInt + 100 + 100
  }

  //  (str: String) => {
  //    str.toInt + 100 + 100
  //  }

  // 定义一个函数funcX，能够接收一个函数func
  // 接收的函数func的类型为  (String,Int) => Int
  // 最终实现对传入的函数func进行调用，并打印返回的结果
  def funcX(func: (String, Int) => Int): Unit = {
    val funcRes: Int = func("100", 200)
    println(funcRes)
  } // 函数式编程之以函数作为参数

  // 定义匿名函数
  // 把func1改造成匿名函数
  (str: String, int: Int) => {
    str.toInt + int
  }

  // 匿名函数也可以拥有名字
  val anonymousFunc: (String, Int) => Int = (str: String, int: Int) => {
    str.toInt + int
  }

  // 定义一个函数funcX2，接收一个函数func，
  // 函数func的类型：String => Int
  // 最终调用func函数，并对结果进行打印
  def funcX2(func: String => Int): Unit = {
    val funcRes: Int = func("100")
    println(funcRes)
  }

  // 函数式编程
  def main(args: Array[String]): Unit = {
    /**
     * 面向对象编程：实际上就是将 对象 传来传去，以对象作为参数或者是返回值，需要考虑类型的限制
     * 面向函数编程：实际上就是将 函数 传来传去，以函数作为参数或者是返回值，需要考虑类型的限制
     *
     * 面向函数编程：
     * 1、以函数作为参数
     * 2、以函数作为返回值
     *
     * 函数的类型跟哪些因素无关？
     * 1、首先跟def关键字无关
     * 2、跟函数名无关
     * 3、跟参数名无关
     * 4、跟函数实现的功能无关
     *
     * 经过排除之后，确定函数的类型跟 参数的类型（跟类型、个数、顺序都有关系）以及返回值的类型有关
     *
     * 函数的类型如何描述？
     * (函数的参数类型1,函数的参数类型2......) => 返回值类型
     * 如果函数的参数只有一个 则括号可以省略
     */

    // 使用funcX检测func1和func3是否为同一种类型的函数
    funcX(func1)
    //    funcX(func2)
    funcX(func3)
    //    funcX(func4)

    // 将匿名函数作为参数 传给funcX
    funcX(anonymousFunc) // 间接传递，先用变量接收匿名函数，再进行传递

    // 直接将匿名函数进行传递
    /**
     * 匿名函数的定义：
     * (参数名:参数类型,参数名:参数类型,参数名:参数类型) => {方法体}
     */
    funcX((str: String, int: Int) => {
      str.toInt + int
    })

    /**
     * 匿名函数的省略规则：
     * 1、如果代码只有一行，则花括号{}可以省略
     * 2、如果匿名函数是作为参数传递给另一个函数，则参数的类型可以省略
     * 3、如果匿名函数的参数只有一个，则括号可以省略
     * 4、如果匿名函数的参数只有一个，并且只被使用了一次，则可以用下划线替代，
     * 并且关于参数声明的部分可以直接省略，以及=>也需要省略
     */
    funcX((str: String, int: Int) => str.toInt + int)
    funcX((str, int) => str.toInt + int)

    funcX2(str => str.toInt + 100)

    funcX2(_.toInt + 100)

  }

}
